package com.learn.excel.core.handler;

import com.learn.excel.core.common.exception.BusinessException;
import com.learn.excel.core.consts.ErrorCode;
import com.learn.excel.core.domain.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * @author: 杜海强
 * @description:
 * @date: 2021/4/16
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BusinessException.class)
    public Response handleBusinessException(HttpServletRequest request, HttpServletResponse response, Exception e) {
        response.setHeader("Access-Control-Allow-Origin", "*");
        BusinessException businessException = (BusinessException) e;
        if (businessException.getLogged()) {
            log.error(businessException.getCode() + ":" + businessException.getMessage(), businessException);
        }
        return Response.fail(businessException.getCode(),
                businessException.getMessage());
    }

    /**
     * 用来处理bean validation异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Response resolveMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletResponse response) {
        log.debug("请求参数校验失败", e);
        response.setHeader("Access-Control-Allow-Origin", "*");
        BindingResult result = e.getBindingResult();
        List<ObjectError> errors = result.getAllErrors();
        String firstError = errors.isEmpty() ? null : errors.iterator().next().getDefaultMessage();
        String errorMessage = StringUtils.isEmpty(firstError) ? ErrorCode.ERR_PARAM_SYSTEM.getErrMsg() : firstError;
        return Response.fail(ErrorCode.ERR_PARAM_SYSTEM.getErrCode(), errorMessage);
    }

    /**
     * 用来处理bean validation异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public Response resolveConstraintViolationException(ConstraintViolationException e) {
        log.debug("请求参数校验失败", e);
        Response result = Response.fail(ErrorCode.ERR_PARAM_SYSTEM.getErrCode(), ErrorCode.ERR_PARAM_SYSTEM.getErrMsg());
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        if (!CollectionUtils.isEmpty(constraintViolations)) {
            StringBuilder msgBuilder = new StringBuilder();
            for (ConstraintViolation constraintViolation : constraintViolations) {
                msgBuilder.append(constraintViolation.getMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if (errorMessage.length() > 1) {
                errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
            }
            result.setMsg(errorMessage);
            return result;
        }
        return result;
    }


    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Response handleException(HttpServletRequest request, HttpServletResponse response, Exception e) {
        String requestUrl = request.getRequestURL().toString();
        log.error("程序异常, 请求地址: {}", requestUrl, e);
        response.setHeader("Access-Control-Allow-Origin", "*");
        return Response.fail(ErrorCode.ERR_CODE_SYSTEM.getErrCode(), ErrorCode.ERR_CODE_SYSTEM.getErrMsg());
    }
}
